/*
 * Unicast.cpp
 *
 *  Created on: 08/ott/2013
 *      Author: alessandrob
 */
#include<iostream>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<opencv2/opencv.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<opencv2/highgui/highgui.hpp>
#include "Utility.h"
#include "brisk/brisk.h"
#define BUFLEN 1400
#define PORT 5002
#define TEST 20

using namespace std;
using namespace cv;

void unicast(int threshold,int octave)
{
	cout<<"Setting up BRISK..."<<endl;
	struct sockaddr_in server_address;
	char ack='f';
	char infoPacket[9];
	int sockfd,dataReceived,i;
	int dataSent,CPUspeed;
	char last;
	Mat picture;
	double det_time,processing_time,sumProc;
	Mat descriptors;
	vector<KeyPoint> kp;

	//Setting up BRISK and first computation

	Ptr<FeatureDetector> detector = new cv::BriskFeatureDetector(threshold,octave);
	Ptr<DescriptorExtractor> descriptorExtractor = new cv::BriskDescriptorExtractor();
  
	/*Codice per stimare la velocità del processore in bit/s (inutile per il client)
  cout<<"Testing cpu speed..."<<endl;
	Mat test = imread("/home/ubuntu/test.jpg",0);
	//first time
	detector->detect(test,kp);
	descriptorExtractor->compute(test,kp,descriptors);
	for(int i=0;i<10;i++)
	{
		det_time=(double)getTickCount();
		detector->detect(test,kp);
		descriptorExtractor->compute(test,kp,descriptors);
		processing_time = ((double)getTickCount() - det_time)/getTickFrequency();
		sumProc+=processing_time;
	}
	CPUspeed = (int)(test.cols*test.rows*8)/(sumProc/10);
	cout<<"CPU speed: "<<CPUspeed<<endl;
	cout<<"Testing keypoints found: "<<kp.size()<<endl;*/
	//CPUspeed = 5000000;
	for(int test = 0;test<TEST;i++)
	{
		cout<<"Setting up TCP client..."<<endl;
		if ((sockfd = socket(AF_INET, SOCK_STREAM, 0))==-1)
			printErrorLog("Client socket not created correctly.");
		cout<<"Client TCP socket created correctly."<<endl;
		bzero(&server_address, sizeof(server_address));
		server_address.sin_family = AF_INET;
		server_address.sin_port = htons(PORT);
		char ip[16];
		memmove(ip,"10.42.0.5",sizeof(ip));
		if(inet_aton(ip,&server_address.sin_addr)==0)
			printErrorLog("IP address not correct");
		cout<<"Ready for the connection..."<<endl;
    //Connessione TCP con il server
		if(connect(sockfd,(const struct sockaddr*)&server_address,sizeof(server_address))<0)
			printErrorLog("Connection refused");
		int cols,rows;
		vector<int> params = vector<int>(2);
		//Waiting for the server synchronization
		char sync;
		cout<<"Waiting for the synchronization"<<endl;
		if(recv(sockfd,&sync,sizeof(char),0)==-1)
			printErrorLog("Synchronization failed");
		//cout<<"Synchronization: done."<<endl;
		if(sync=='s')
		{
			//Setting up local timer
			cout<<"Client synchronized. Timer started"<<endl;
			det_time=(double)getTickCount();
			//Waiting for the image size
			if(recv(sockfd,&infoPacket[0],sizeof(char)*9,0)!=sizeof(char)*9)
				printErrorLog("Info packet not received correctly.");
			cols = (infoPacket[0] << 24);
			cols = cols + (infoPacket[1] << 16);
			cols = cols + (infoPacket[2] << 8);
			cols = cols + (infoPacket[3]);
			rows = (infoPacket[4] << 24);
			rows = rows + (infoPacket[5] << 16);
			rows = rows + (infoPacket[6] << 8);
			rows = rows + (infoPacket[7]);
			last = infoPacket[8];
			double cols_time = ((double)getTickCount()-det_time)/getTickFrequency();
			cout<<"Receiving info packet time: T+"<<cols_time*1000<<"ms"<<endl;
			uchar imageArray[cols*rows];
			double starttime = ((double)getTickCount()-det_time)/getTickFrequency();
			cout<<"Ready for receiving data. Time: T+"<<starttime*1000<<"ms"<<endl;
			dataReceived = recv(sockfd,&imageArray[0],cols*rows,MSG_WAITALL);
			double receivingtime = ((double)getTickCount()-det_time)/getTickFrequency();
			cout<<"Receiving time: T+"<<receivingtime*1000<<"ms"<<endl;
			if(dataReceived!=cols*rows)
				printErrorLog("Data not received correctly");
			cout<<"Data correctly received"<<endl;
			//Invio dell'ACK al server se sono l'ultimo client in ordine di connessione.
			if(last==1)
			{
				if(send(sockfd, &ack , sizeof(char), 0)!=sizeof(char))
					printErrorLog("ACK not sent correctly");
				cout<<"ACK sent correctly"<<endl;
				double ack_time = ((double)getTickCount()-det_time)/getTickFrequency();
				cout<<"ACK time: T+"<<ack_time*1000<<"ms"<<endl;
			}
			picture = Mat(rows,cols,CV_8UC1,imageArray,cols);
			double openingtime = ((double)getTickCount()-det_time)/getTickFrequency();
			cout<<"Opening time: T+"<<openingtime*1000<<"ms"<<endl;

			//Compute BRISK
			Mat distributedKp;
			double sum=0;
			int size;
			detector->detect(picture,kp);
			descriptorExtractor->compute(picture,kp,descriptors);
			double final_time=((double)getTickCount()-det_time)/getTickFrequency();
			cout<<"Final time: T+"<<final_time*1000<<"ms"<<endl;
			size = kp.size();
			cout<<"Keypoints detected: "<<size<<endl;
			vector<int> params = vector<int>(1);
			params[0]=0;
			cout<<"SENDING DATA TO THE SERVER..."<<endl;
			sendData(sockfd,final_time,size,kp,descriptors);
		}
		close(sockfd);
		sleep(5);
	}
}


